#ifndef DERIVATIONTREE_H
#define DERIVATIONTREE_H
#include "LeonardVirtualMachine.h"
#include "Expression.h"
#include "Pointer.h"

class NodeTree {
public:
	virtual bool execute(Pointer<LeonardVirtualMachine>) = 0;
	virtual NodeTree* clone() const = 0;
};

template<typename  Derived> class NodeTree_CRTP: public virtual NodeTree {
public:
	NodeTree_CRTP() : NodeTree() { }
	NodeTree_CRTP(const NodeTree_CRTP& copy) : NodeTree(copy) { }//TODO template argument?

	NodeTree* clone() const {
		return new Derived(dynamic_cast<Derived const&>(*this));
	}
};

class BaseTree : public NodeTree_CRTP<BaseTree> {
public:
	BaseTree();
	BaseTree(const BaseTree&);

	bool execute(Pointer<LeonardVirtualMachine>);

private:
	AutoPointer<NodeTree> son;
};

class PlusNode : public NodeTree_CRTP<PlusNode> {
public:
	PlusNode();
	PlusNode(const AutoPointer<NodeTree>&, const AutoPointer<NodeTree>&);
	PlusNode(const PlusNode&);

	bool execute(Pointer<LeonardVirtualMachine>);

private:
	AutoPointer<NodeTree> left;
	AutoPointer<NodeTree> right;
};

class StarNode : public NodeTree_CRTP<StarNode> {
public:
	StarNode();
	StarNode(const AutoPointer<NodeTree>&, const AutoPointer<NodeTree>&);
	StarNode(const StarNode&);

	bool execute(Pointer<LeonardVirtualMachine>);

private:
	AutoPointer<NodeTree> left;
	AutoPointer<NodeTree> right;
};

class DivideNode : public NodeTree_CRTP<DivideNode> {
public:
	DivideNode();
	DivideNode(const AutoPointer<NodeTree>&, const AutoPointer<NodeTree>&);
	DivideNode(const DivideNode&);

	bool execute(Pointer<LeonardVirtualMachine>);

private:
	AutoPointer<NodeTree> left;
	AutoPointer<NodeTree> right;
};

class PowerNode : public NodeTree_CRTP<PowerNode> {
public:
	PowerNode();
	PowerNode(const AutoPointer<NodeTree>&, const AutoPointer<NodeTree>&);
	PowerNode(const PowerNode&);

	bool execute(Pointer<LeonardVirtualMachine>);

private:
	AutoPointer<NodeTree> left;
	AutoPointer<NodeTree> right;
};

class MinusNode : public NodeTree_CRTP<MinusNode> {
public:
	MinusNode();
	MinusNode(const AutoPointer<NodeTree>&, const AutoPointer<NodeTree>&);
	MinusNode(const MinusNode&);

	bool execute(Pointer<LeonardVirtualMachine>);

private:
	AutoPointer<NodeTree> left;
	AutoPointer<NodeTree> right;
};

class UnaryMinusNode : public NodeTree_CRTP<UnaryMinusNode> {
public:
	UnaryMinusNode();
	UnaryMinusNode(const AutoPointer<NodeTree>&);
	UnaryMinusNode(const UnaryMinusNode&);

	bool execute(Pointer<LeonardVirtualMachine>);

private:
	AutoPointer<NodeTree> argument;
};

class IntegerNode : public NodeTree_CRTP<IntegerNode> {
public:
	IntegerNode();
	IntegerNode(char*, unsigned int);
	IntegerNode(const IntegerNode&);

	bool execute(Pointer<LeonardVirtualMachine>);
private:
	char* buffer;
	unsigned int length;
};

class FloatNode : public NodeTree_CRTP<FloatNode> {
public:
	FloatNode();
	FloatNode(char*, unsigned int);
	FloatNode(const FloatNode&);

	bool execute(Pointer<LeonardVirtualMachine>);
private:
	char* buffer;
	unsigned int length;
};

class VariableNode : public NodeTree_CRTP<VariableNode> {
public:
	VariableNode();
	VariableNode(char*, unsigned int);
	VariableNode(const VariableNode&);

	bool execute(Pointer<LeonardVirtualMachine>);

	std::string getName() const;
private:
	char* buffer;
	unsigned int length;
};

class EqualNode : public NodeTree_CRTP<EqualNode> {
public:
	EqualNode();
	EqualNode(const AutoPointer<NodeTree>&, const AutoPointer<NodeTree>&);
	EqualNode(const EqualNode&);

	bool execute(Pointer<LeonardVirtualMachine>);

private:
	AutoPointer<NodeTree> left;
	AutoPointer<NodeTree> right;
};

class ColonNode : public NodeTree_CRTP<ColonNode> {
public:
	ColonNode();
	ColonNode(const AutoPointer<NodeTree>&, const AutoPointer<NodeTree>&);
	ColonNode(const ColonNode&);

	bool execute(Pointer<LeonardVirtualMachine>);

private:
	AutoPointer<NodeTree> left;
	AutoPointer<NodeTree> right;
};

class FunctionCallNode : public NodeTree_CRTP<FunctionCallNode> {
public:
	FunctionCallNode();
	FunctionCallNode(char*, unsigned int);
	FunctionCallNode(const FunctionCallNode&);

	bool execute(Pointer<LeonardVirtualMachine>);

	std::string getName() const;
private:
	char* buffer;
	unsigned int length;
};

class ParameterFunctionNode : public NodeTree_CRTP<ParameterFunctionNode> {
public:
	ParameterFunctionNode();
	ParameterFunctionNode(const AutoPointer<NodeTree>&, const AutoPointer<NodeTree>&);
	ParameterFunctionNode(const ParameterFunctionNode&);

	bool execute(Pointer<LeonardVirtualMachine>);

private:
	AutoPointer<NodeTree> left;
	AutoPointer<NodeTree> right;
};

class FunctionNameDefinitionNode : public NodeTree_CRTP<FunctionNameDefinitionNode> {
public:
	FunctionNameDefinitionNode();
	FunctionNameDefinitionNode(char*, unsigned int);
	FunctionNameDefinitionNode(const FunctionNameDefinitionNode&);

	bool execute(Pointer<LeonardVirtualMachine>);

	std::string getName() const;
private:
	char* buffer;
	unsigned int length;
};

class FunctionDefinitionNode : public NodeTree_CRTP<FunctionDefinitionNode> {
public:
	FunctionDefinitionNode();
	FunctionDefinitionNode(const FunctionDefinitionNode&);

	void setName(const AutoPointer<NodeTree>&);
	void addInstruction(const AutoPointer<NodeTree>&);
	void addParameter(const AutoPointer<NodeTree>&);

	bool execute(Pointer<LeonardVirtualMachine>);

private:
	AutoPointer<NodeTree> name;
	std::list< AutoPointer<NodeTree> > listInstruction;
	std::list< AutoPointer<NodeTree> > listParameter;
};

class ReturnNode : public NodeTree_CRTP<ReturnNode> {
public:
	ReturnNode(const AutoPointer<NodeTree>&);
	ReturnNode(const ReturnNode&);

	bool execute(Pointer<LeonardVirtualMachine>);

private:
	AutoPointer<NodeTree> returnNode;
};

class TypeParameterNode : public NodeTree_CRTP<TypeParameterNode> {
public:
	TypeParameterNode();
	TypeParameterNode(char*, unsigned int);
	TypeParameterNode(const TypeParameterNode&);

	bool execute(Pointer<LeonardVirtualMachine>);

	std::string getName() const;
private:
	char* buffer;
	unsigned int length;
};

class ParameterNameNode : public NodeTree_CRTP<ParameterNameNode> {
public:
	ParameterNameNode();
	ParameterNameNode(char*, unsigned int);
	ParameterNameNode(const ParameterNameNode&);

	bool execute(Pointer<LeonardVirtualMachine>);

	std::string getName() const;
private:
	char* buffer;
	unsigned int length;
};

class BoolSymbolNode : public NodeTree_CRTP<BoolSymbolNode> {
public:
	BoolSymbolNode();
	BoolSymbolNode(char*, unsigned int);
	BoolSymbolNode(const BoolSymbolNode&);

	bool execute(Pointer<LeonardVirtualMachine>);

	std::string getName() const;
private:
	char* buffer;
	unsigned int length;
};

class BooleanNode : public NodeTree_CRTP<BooleanNode> {
public:
	BooleanNode();
	BooleanNode(const AutoPointer<NodeTree>&, const AutoPointer<NodeTree>&, const AutoPointer<NodeTree>&);
	BooleanNode(const BooleanNode&);

	bool execute(Pointer<LeonardVirtualMachine>);

private:
	AutoPointer<NodeTree> left;
	AutoPointer<NodeTree> right;
	AutoPointer<NodeTree> symbol;
};

class IfNode : public NodeTree_CRTP<IfNode> {
public:
	IfNode();
	IfNode(const IfNode&);

	void setHasCondition(bool);
	void setCondition(const AutoPointer<NodeTree>&);
	void addInstruction(const AutoPointer<NodeTree>&);

	bool execute(Pointer<LeonardVirtualMachine>);
private:
	bool hasCondition;
	AutoPointer<NodeTree> condition;
	std::list< AutoPointer<NodeTree> > listInstruction;
};

class ElseNode : public NodeTree_CRTP<ElseNode> {
public:
	ElseNode();
	ElseNode(const ElseNode&);

	void setEndElse(const AutoPointer<NodeTree>&);
	void addElse(const AutoPointer<NodeTree>&);

	bool execute(Pointer<LeonardVirtualMachine>);

private:
	AutoPointer<NodeTree> endElse;
	std::list< AutoPointer<NodeTree> > listElse;
};

class WhileNode : public NodeTree_CRTP<WhileNode> {
public:
	WhileNode();
	WhileNode(const WhileNode&);

	void setCondition(const AutoPointer<NodeTree>&);
	void addInstruction(const AutoPointer<NodeTree>&);

	bool execute(Pointer<LeonardVirtualMachine>);

private:
	AutoPointer<NodeTree> condition;
	std::list< AutoPointer<NodeTree> > listInstruction;
};

#endif
